/*
 * io.c
 *
 *  Created on: 2017年5月1日
 *      Author: chenss
 */


#include "io.h"
#include "serial.h"
#include "shell.h"
#include "chprintf.h"
#include "ctimer.h"
#include "utils.h"

#include "io/led.h"
#include "io/lock.h"
#include "io/lighting.h"
#include "io/adc.h"
#include "io/beep.h"
#include "io/vibration.h"
#include "io/volume.h"
#include "io/ir_detect.h"
#include "io/watchdog.h"

#include <string.h>
#include <stdlib.h>

#define LIGHTING_IO IO(B, 6)
#define BEEP_IO IO(B, 9)

struct IoNotify
{
    IO_t io;
    int value;
};

//static int _ioValues[IO_Max + 1];
//static Ctimer_t _timer;


//static void _OnTimeout(void);
static void _GsmEnInit(void);

void IO_Init(void)
{

//    memset(_ioValues, 0, sizeof(_ioValues));
//    _ioValues[IO_AlarmTimeLenght] = 2;

    _GsmEnInit();
    Led_Init();
    Lock_Init();
    Lighting_Init();
    Adc_Init();
    Beep_Init();
    Vibration_Init();
    Volume_Init();
    IrDetect_Init();
    WatchDog_Init();
}

static void _GsmEnInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_SetBits(GPIOA, GPIO_Pin_10);
}

//static void _OnTimeout(void)
//{
//    IO_Set(IO_Null, 1);
//}

int IO_ShellSet(Stream_t *stream, int argc, char *argv[])
{
    IO_t io;
    int value, i;
    Stream_t *comStream;

    if(argc < 3)
    {
        return -1;
    }

    io = atoi(argv[1]);
    if(io == IO_Null)
    {
        debug("Setting NULL IO\r\n");
    }
    else if(io > IO_Max)
    {
        return -1;
    }

    for(i = 2; i < argc; i++)
    {
        value = atoi(argv[i]);
        IO_RemoteSet(io, value);
        MsgQueue_Send(MsgQueue_Id_IoUpdate, & io, sizeof(io));
        io++;
    }

    comStream = Serial_ComStream();
    if(stream != comStream)
    {
        chprintf(comStream, "\r\n");
        for(i = 0; i < argc; i++)
        {
            chprintf(comStream, "%s ", argv[i]);
        }
        chprintf(comStream, "\r\n");
    }

    return 0;
}

int IO_ShellGet(Stream_t *stream, int argc, char *argv[])
{
    IO_t io, ioFrom, ioTo;

    if(argc < 2)
    {
        return -1;
    }

    ioFrom = atoi(argv[1]);
    if(ioFrom == IO_Null)
    {
        debug("Getting NULL IO\r\n");
    }
    else if(ioFrom > IO_Max)
    {
        return -1;
    }

    chprintf(stream, "\r\n");
    if(argc >= 3)
    {
        ioTo = atoi(argv[2]);
        if(ioTo > ioFrom)
        {
            if(ioTo > IO_Max)
            {
                ioTo = IO_Max;
            }

            chprintf(stream, "SETIO %d", ioFrom);
            for(io = ioFrom; io <= ioTo; io++)
            {
                chprintf(stream, " %d", IO_RemoteGet(io));
//                chprintf(stream, "SETIO %d %d\r\n", io, io);
//                Utils_DelayMs(10);
            }
            chprintf(stream, "\r\n");

            return 0;
        }
    }

    chprintf(stream, "SETIO %d %d\r\n", ioFrom, IO_RemoteGet(ioFrom));

    return 0;
}

void IO_Changed(IO_t io, int value)
{
    struct IoNotify notify;

    notify.io = io;
    notify.value = value;
    MsgQueue_Send(MsgQueue_Id_IoNotyfyRemote, & notify, sizeof(notify));
}

void IO_OnNotify(MsgQueue_Msg_t *msg)
{
    struct IoNotify *notify;

    notify = (struct IoNotify *) msg->data;

    chprintf(Serial_ComStream(), "\r\nSETIO %d %d\r\n", notify->io, notify->value);
}

//int IO_Get(IO_t io)
//{
//    return _ioValues[io];
//}

void IO_Request(IO_t io)
{
    chprintf(Serial_ComStream(), "\r\nGETIO %d\r\n", io);
}

void IO_RemoteSet(IO_t io, int value)
{
//    _ioValues[io] = value;

    switch(io)
    {
    case IO_Lighting:
        Lighting_Set(value);
        break;

    case IO_Lock1:
    case IO_Lock2:
    case IO_Lock3:
        Lock_Set(Lock_1 + (io - IO_Lock1), 1);
        break;

    case IO_Led:
        Led_Set(value);
        break;

    case IO_Vibration:
        Vibration_Set(value);
        break;

    case IO_Beep:
        Beep_Set(value);
        break;

    case IO_WatchDogValue:
        WatchDog_Set(0);
        break;

    case IO_VibrationFreq:
    case IO_Volume:
    case IO_Vbat:
    case IO_IrDetectStatus:
        break;

    default:
        debug("Setting unknown IO: %d\r\n", io);
        break;
    }
}

int IO_RemoteGet(IO_t io)
{
    int value = 0;

    switch(io)
    {
    case IO_Lighting:
        value = Lighting_Get();
        break;

    case IO_Lock1:
    case IO_Lock2:
    case IO_Lock3:
        value = Lock_Get(Lock_1 + (io - IO_Lock1));
        break;

    case IO_Vibration:
        value = Vibration_Get();
        break;

    case IO_VibrationFreq:
        value = Vibration_GetFreq();
        break;

    case IO_Led:
        value = Led_Get();
        break;

    case IO_Volume:
        value = Volume_Get();
        break;

    case IO_Vbat:
        value = Adc_GetVbat();
        break;

    case IO_Beep:
        break;

    case IO_IrDetectStatus:
        value = IrDetect_Get();
        break;

    case IO_WatchDogValue:
        value = WatchDog_Get();
        break;

    default:
        debug("Getting unknown IO: %d\r\n", io);
        break;
    }

    return value;
}

void EXTI4_15_IRQHandler(void)
{
    Lock_StatusScan();
    Vibration_EXTI12Handler();
    IrDetect_Exti13N14Handler();
}

void IO_OnVibrationUpdate(MsgQueue_Msg_t *msg)
{
    int freq;

    freq = *((typeof(freq) *) msg->data);
    IO_Changed(IO_VibrationFreq, freq);
    debug("Vibration freq: %d\r\n", freq);
}

void IO_OnMonitor(void)
{
//    int value;
//
//    value = Adc_GetVbat();
//    IO_Changed(IO_Vbat, value);
//
//    value = Volume_Get();
//    IO_Changed(IO_Volume, value);
}
